import { throttle, cssSupported } from 'utils'

const ctx = '@@sticky'

function getScrollEventTarget(element) {
  let currentNode = element

  while (currentNode
    && currentNode.tagName !== 'HTML'
    && currentNode.tagName !== 'BODY'
    && currentNode.nodeType === 1
  ) {
    const overflowY = window.getComputedStyle(currentNode).overflowY
    if (overflowY === 'scroll' || overflowY === 'auto') {
      return currentNode
    }
    currentNode = currentNode.parentNode
  }
  return window
}

function getScrollTop(element) {
  if (element === window) {
    return Math.max(window.pageYOffset || 0, document.documentElement.scrollTop)
  }
  return element.scrollTop
}

function getElementTop(element) {
  if (element === window) {
    return getScrollTop(window)
  }
  return element.getBoundingClientRect().top + getScrollTop(window)
}

function handler() {
  const scrollEventTarget = this.scrollEventTarget
  const element = this.el
  const elementTop = this.elementTop

  if (getElementTop(scrollEventTarget) > elementTop) {
    element.style.position = 'fixed'
  } else {
    element.style.position = 'static'
  }
}

function doBind() {
  if (this.binded) return
  this.binded = true

  const directive = this
  const element = directive.el

  directive.elementTop = element.offsetTop
  directive.scrollEventTarget = getScrollEventTarget(element)
  directive.scrollListener = throttle(handler.bind(directive), 50)
  directive.scrollEventTarget.addEventListener('scroll', directive.scrollListener)
}

export default {
  bind(el, binding, vnode) {
    const vm = vnode.context
    const expression = binding.value || {}
    el[ctx] = {
      el,
      vm,
      expression,
    }

    vm.$on('hook:mounted', () => {
      const isSupportedSticky = cssSupported('position', 'sticky')
      const top = expression.top || '0px'
      const zIndex = expression.zIndex || '1000'

      el.style.top = top
      el.style.zIndex = zIndex

      if (isSupportedSticky) {
        el.style.position = '-webkit-sticky'
        el.style.position = 'sticky'
      } else {
        el.style.position = 'static'
        doBind.call(el[ctx])
      }
    })
  },

  unbind(el) {
    if (el[ctx].scrollEventTarget) {
      el[ctx].scrollEventTarget.removeEventListener('scroll', el[ctx].scrollListener)
    }
  },
}
